home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / SMTPCLI.C < prev    next >
C/C++ Source or Header  |  1993-10-03  |  19KB  |  835 lines

  1. /*
  2.  *    CLIENT routines for Simple Mail Transfer Protocol ala RFC821
  3.  *    A.D. Barksdale Garbee II, aka Bdale, N3EUA
  4.  *    Copyright 1986 Bdale Garbee, All Rights Reserved.
  5.  *    Permission granted for non-commercial copying and use, provided
  6.  *    this notice is retained.
  7.  *     Modified 14 June 1987 by P. Karn for symbolic target addresses,
  8.  *    also rebuilt locking mechanism
  9.  *    Copyright 1987 1988 David Trulli, All Rights Reserved.
  10.  *    Permission granted for non-commercial copying and use, provided
  11.  *    this notice is retained.
  12.  */
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <time.h>
  16. #include <setjmp.h>
  17. #include <ctype.h>
  18. #include <sys/stat.h>
  19. #ifdef    __TURBOC__
  20. #include <dir.h>
  21. #include <io.h>
  22. #endif
  23. #include "global.h"
  24. #include "config.h"
  25. #ifdef    ANSIPROTO
  26. #include <stdarg.h>
  27. #endif
  28. #include "cmdparse.h"
  29. #include "proc.h"
  30. #include "socket.h"
  31. #ifdef LZW
  32. #include "lzw.h"
  33. #endif
  34. #include "timer.h"
  35. #include "netuser.h"
  36. #include "smtp.h"
  37. #include "dirutil.h"
  38. #include "commands.h"
  39. #include "session.h"
  40. #include "files.h"
  41. #include "event.h"
  42. #include "server.h"
  43.  
  44. #undef    SMTPTRACE    1
  45.  
  46. int16 Smtpquiet = 0;
  47. int Smtpmode = ROUTE;
  48. int Smtpbbs = BBS;
  49.  
  50. static int Smtpsessions = 0;        /* number of client connections */
  51. static int16 Smtpmaxcli = MAXSESSIONS;    /* the max client connections allowed */
  52.  
  53. static struct smtpcli *Smtpcli = NULLSMTPCLI;
  54.  
  55. #ifdef SMTPTRACE
  56. static int Smtptrace = FALSE;        /* used for trace level */
  57. #endif
  58.  
  59. #ifdef LZW
  60. int Smtplzw = TRUE;
  61. static int Smtpbatch = TRUE;
  62. #else
  63. static int Smtpbatch = FALSE;
  64. #endif
  65.  
  66. static void near
  67. del_job(struct smtp_job *jp)
  68. {
  69.     if(*jp->jobname != '\0') {
  70.         rmlock(Mailqdir,jp->jobname);
  71.     }
  72.     xfree(jp->from);
  73.     del_list(jp->to);
  74.     xfree(jp);
  75. }
  76.  
  77. /* free the message struct and data */
  78. static void near
  79. del_session(struct smtpcli *cb)
  80. {
  81.     struct smtpcli *sm, *smtmp = NULLSMTPCLI;
  82.     struct smtp_job *jp, *jptmp = NULLJOB;
  83.  
  84.     for(sm = Smtpcli; sm != NULLSMTPCLI; smtmp = sm, sm = sm->next) {
  85.         if(sm == cb) {
  86.             break;
  87.         }
  88.     }
  89.     if(sm == NULLSMTPCLI) {
  90.         /* Not found */
  91.         return;
  92.     }
  93.     /* Remove from list */
  94.     if(smtmp != NULLSMTPCLI) {
  95.         smtmp->next = sm->next;
  96.     } else {
  97.         Smtpcli = sm->next;
  98.     }
  99.     xfree(cb->destname);
  100.     xfree(cb->tname);
  101.     xfree(cb->wname);
  102.     xfree(cb->buf);
  103.  
  104.     for(jp = cb->jobq; jp != NULLJOB; jp = jptmp) {
  105.         jptmp = jp->next;
  106.         del_job(jp);
  107.     }
  108.  
  109.     del_list(cb->errlog);
  110.     xfree(cb);
  111.     Smtpsessions--;    /* number of connections active */
  112. }
  113.  
  114. /* called to advance to the next job */
  115. static int near
  116. next_job(struct smtpcli *cb)
  117. {
  118.     struct smtp_job *jp = cb->jobq->next;
  119.  
  120.     del_job(cb->jobq);
  121.  
  122.     /* remove the error log of previous message */
  123.     del_list(cb->errlog);
  124.     cb->errlog = NULLLIST;
  125.     cb->jobq = jp;
  126.  
  127.     if (jp == NULLJOB) {
  128.         return 0;
  129.     }
  130.     sprintf(cb->tname,"%s/%s.txt",Mailqdir,jp->jobname);
  131.     sprintf(cb->wname,"%s/%s.wrk",Mailqdir,jp->jobname);
  132.  
  133. #ifdef SMTPTRACE
  134.     if (Smtptrace) {
  135.         tprintf("SMTP sending job %s\n",jp->jobname);
  136.     }
  137. #endif
  138.     return 1;
  139. }
  140.  
  141. /* add this job to control block queue */
  142. static struct smtp_job * near
  143. setupjob(struct smtpcli *cb,char *id,char *from)
  144. {
  145.     struct smtp_job *p2, *p1 = mxallocw(sizeof(struct smtp_job));
  146.  
  147.     strcpy(p1->jobname,id);
  148.     p1->from = strxdup(from);
  149.  
  150.     /* now add to end of jobq */
  151.     if ((p2 = cb->jobq) == NULLJOB) {
  152.         cb->jobq = p1;
  153.     } else {
  154.         while(p2->next != NULLJOB) {
  155.             p2 = p2->next;
  156.         }
  157.         p2->next = p1;
  158.     }
  159.     return p1;
  160. }
  161.  
  162. /* stub for calling mdaemon to return message to sender */
  163. static void near
  164. retmail(struct smtpcli *cb)
  165. {
  166.     FILE *infile;
  167.  
  168. #ifdef SMTPTRACE
  169.     if(Smtptrace) {
  170.         tprintf("SMTP job %s returned to sender\n",cb->wname);
  171.     }
  172. #endif
  173.     if((infile = Fopen(cb->tname,READ_TEXT,0,0)) != NULLFILE) {
  174.         mdaemon(infile,cb->jobq->from,cb->errlog,1);
  175.         Fclose(infile);
  176.     }
  177. }
  178.  
  179. /* save line in error list */
  180. static void near
  181. logerr(struct smtpcli *cb,char *line)
  182. {
  183.     struct list *lp, *tp = mxallocw(sizeof(struct list));
  184.  
  185.     tp->val = strxdup(line);
  186.  
  187.     /* find end of list */
  188.     if ((lp = cb->errlog) == NULLLIST) {
  189.         cb->errlog = tp;
  190.     } else {
  191.         while(lp->next != NULLLIST) {
  192.             lp = lp->next;
  193.         }
  194.         lp->next = tp;
  195.     }
  196. }
  197.  
  198. /* Wait for, read and display response from server.
  199.  * Return the result code.
  200.  * Keep reading until at least this code comes back.
  201.  */
  202. static int near
  203. getresp(struct smtpcli *cb,int mincode)
  204. {
  205.     int rval = -1;
  206.     char line[LINELEN];
  207.  
  208.     usflush(cb->s);
  209.  
  210.     for(;;){
  211.         /* Get line */
  212.         if(recvline(cb->s,line,sizeof(line)) == -1) {
  213.             break;
  214.         }
  215.         rip(line);                /* Remove cr/lf */
  216.         rval = atoi(line);
  217.  
  218. #ifdef SMTPTRACE
  219.         if(Smtptrace) {
  220.             tprintf("SMTP recv: %s\n",line);/* Display to user */
  221.         }
  222. #endif
  223.         if(rval >= 500) {    /* Save permanent error replies */
  224.             char tmp[LINELEN];
  225.  
  226.             if(cb->errlog == NULLLIST) {
  227.                 sprintf(tmp,"While talking to %s:",cb->destname);
  228.                 logerr(cb,tmp);
  229.             }
  230.             if(cb->buf[0] != '\0') {    /* Save offending command */
  231.                 rip(cb->buf);
  232.                 sprintf(tmp,">>> %s",cb->buf);
  233.                 logerr(cb,tmp);
  234.                 cb->buf[0] = '\0';
  235.             }
  236.             sprintf(tmp,"<<< %s",line);
  237.             logerr(cb,tmp);        /* save the error reply */
  238.         }
  239.         /* Messages with dashes are continued */
  240.         if(line[3] != '-' && rval >= mincode) {
  241.             break;
  242.         }
  243.     }
  244.     return rval;
  245. }
  246.  
  247. /* This is the master state machine that handles a single SMTP transaction.
  248.  * It is called with a queue of jobs for a particular host.
  249.  * The logic is complicated by the "Smtpbatch" variable, which controls
  250.  * the batching of SMTP commands. If Smtpbatch is true, then many of the
  251.  * SMTP commands are sent in one swell foop before waiting for any of
  252.  * the responses. Unfortunately, this breaks many brain-damaged SMTP servers
  253.  * out there, so provisions have to be made to operate SMTP in lock-step mode.
  254.  */
  255. static void
  256. smtp_send(int unused,void *cb1,void *p)
  257. {
  258.     struct list *tp;
  259.     struct sockaddr_in fsocket;
  260.     char *cp;
  261.     int smtpbatch, rcode, rcpts, goodrcpt, i, init = 1;
  262.     struct smtpcli *cb = (struct smtpcli *)cb1;
  263.  
  264.     cb->lock = 1;
  265.  
  266.     fsocket.sin_family = AF_INET;
  267.     fsocket.sin_addr.s_addr = cb->ipdest;
  268.     fsocket.sin_port = IPPORT_SMTP;
  269.  
  270.     if((cb->s = socket(AF_INET,SOCK_STREAM,0)) == -1) {
  271.         tputs(Nosocket);
  272.         return;
  273.     }
  274. #ifdef SMTPTRACE
  275.     if(Smtptrace) {
  276.         tprintf("SMTP client Trying %s...\n",psocket((struct sockaddr *)&fsocket));
  277.     }
  278. #endif
  279.     if(connect(cb->s,(char *)&fsocket,SOCKSIZE) == -1) {
  280.         if((cp = sockerr(cb->s)) == NULLCHAR) {
  281.             cp = "EOF";
  282.         }
  283. #ifdef SMTPTRACE
  284.         if(Smtptrace) {
  285.             tprintf("SMTP connect failed: %s\n",cp);
  286.         }
  287. #endif
  288.         log(cb->s,9983,"SMTP %s Connect failed: %s",psocket((struct sockaddr *)&fsocket),cp);
  289.         close_s(cb->s);
  290.         del_session(cb);
  291.         return;
  292.     }
  293. #ifdef SMTPTRACE
  294.     if(Smtptrace) {
  295.         tputs("SMTP connected\n");
  296.     }
  297. #endif
  298.     sockmode(cb->s,SOCK_ASCII);
  299.  
  300.     smtpbatch = Smtpbatch;
  301.  
  302. #ifdef LZW
  303.     rcode = getresp(cb,200);
  304.     if(rcode == -1 || rcode >= 400) {
  305.         goto quit;
  306.     }
  307.     /* disable LZW to ourselve */
  308.     if(Smtplzw && cb->ipdest != Ip_addr) {
  309.         char cp[LINELEN];
  310.  
  311.         usprintf(cb->s,"XLZW %d %d\n",Lzwbits,Lzwmode);
  312.  
  313.         if(recvline(cb->s,cp,LINELEN) == -1) {
  314.             goto quit;
  315.         }
  316.         if((rcode = atoi(cp)) == 252) {
  317.             lzwinit(cb->s,Lzwbits,Lzwmode);
  318.             smtpbatch = 1;
  319.         }
  320.     }
  321. #else
  322.     if(!smtpbatch) {
  323.         rcode = getresp(cb,200);
  324.         if(rcode == -1 || rcode >= 400) {
  325.             goto quit;
  326.         }
  327.     }
  328. #endif
  329.  
  330.     /* Say HELO */
  331.     usprintf(cb->s,"HELO %s\n",Hostname);
  332.  
  333.     if(!smtpbatch){
  334.         rcode = getresp(cb,200);
  335.         if(rcode == -1 || rcode >= 400) {
  336.             goto quit;
  337.         }
  338.     }
  339.     do {    /* For each message... */
  340.         /* if this file open fails, skip it */
  341.         if ((cb->tfile = Fopen(cb->tname,READ_TEXT,0,0)) == NULLFILE) {
  342.             continue;
  343.         }
  344.         /* Send MAIL and RCPT commands */
  345.         usprintf(cb->s,"MAIL FROM:<%s>\n",cb->jobq->from);
  346.  
  347.         if(!smtpbatch) {
  348.             rcode = getresp(cb,200);
  349.             if(rcode == -1 || rcode >= 400) {
  350.                 goto quit;
  351.             }
  352.         }
  353.         rcpts = 0;
  354.         goodrcpt = 0;
  355.  
  356.         for(tp = cb->jobq->to; tp != NULLLIST; tp = tp->next) {
  357.             usprintf(cb->s,"RCPT TO:<%s>\n",tp->val);
  358.  
  359.             if(!smtpbatch){
  360.                 rcode = getresp(cb,200);
  361.                 if(rcode == -1) {
  362.                     goto quit;
  363.                 }
  364.                 if(rcode >= 400) {
  365.                     continue;
  366.                 }
  367.                 goodrcpt = 1; /* At least one good */
  368.             }
  369.             rcpts++;
  370.         }
  371.         /* Send DATA command */
  372.         usputs(cb->s,"DATA\n");
  373.  
  374.         if(!smtpbatch) {
  375.             rcode = getresp(cb,200);
  376.             if(rcode == -1 || rcode >= 400) {
  377.                 goto quit;
  378.             }
  379.         }
  380.         if(smtpbatch){
  381.             /* Now wait for the responses to come back. The first time
  382.              * we do this, we wait first for the start banner and
  383.              * HELO response. In any case, we wait for the response to
  384.              * the MAIL command here.
  385.              */
  386. #ifdef LZW
  387.             for(i = init ? 2 : 1; i > 0; i--) {
  388. #else
  389.             for(i = init ? 3 : 1; i > 0; i--) {
  390. #endif
  391.                 rcode = getresp(cb,200);
  392.                 if(rcode == -1 || rcode >= 400) {
  393.                     goto quit;
  394.                 }
  395.             }
  396.             init = 0;
  397.  
  398.             /* Now process the responses to the RCPT commands */
  399.             for(i = rcpts; i != 0; i--) {
  400.                 rcode = getresp(cb,200);
  401.  
  402.                 if(rcode == -1) {
  403.                     goto quit;
  404.                 }
  405.                 if(rcode < 400) {
  406.                     goodrcpt = 1; /* At least one good */
  407.                 }
  408.             }
  409.             /* And finally get the response to the DATA command.
  410.              * Some servers will return failure here if no recipients
  411.              * are valid, some won't.
  412.              */
  413.             rcode = getresp(cb,200);
  414.  
  415.             if(rcode == -1 || rcode >= 400) {
  416.                 goto quit;
  417.             }
  418.             /* check for no good rcpt on the list */
  419.             if(goodrcpt == 0) {
  420.                 usputs(cb->s,".\n");  /* Get out of data mode */
  421.                 goto quit;
  422.             }
  423.         }
  424.         /* Send the file. This also closes it */
  425.         while(fgets(cb->buf,LINELEN,cb->tfile) != NULL) {
  426.             /* Escape a single '.' character at the beginning of a line */
  427.             if(strcmp(cb->buf,".\n") == 0) {
  428.                 usputs(cb->s,".");
  429.             }
  430.             usputs(cb->s,cb->buf);
  431.         }
  432.         Fclose(cb->tfile);
  433.         cb->tfile = NULLFILE;
  434.  
  435.         /* Send the end-of-message command */
  436.         usprintf(cb->s,"%s.\n",(cb->buf[strlen(cb->buf)-1] == '\n') ? "" : "\n");
  437.  
  438.         /* Wait for the OK response */
  439.         if((rcode = getresp(cb,200)) == -1) {
  440.             goto quit;
  441.         }
  442.         if((rcode >= 200 && rcode < 300) || rcode >= 500){
  443.             /* if a good transfer or permanent failure remove job */
  444.             if(cb->errlog != NULLLIST) {
  445.                 retmail(cb);
  446.             }
  447.             unlink(cb->tname);
  448.             unlink(cb->wname);
  449.  
  450.             log(cb->s,IPPORT_SMTP,
  451.               "SMTP sent job %s To: %s From: %s",
  452.               cb->jobq->jobname,cb->jobq->to->val,cb->jobq->from);
  453.         }
  454.     } while(next_job(cb));
  455. quit:
  456.     usputs(cb->s,"QUIT\n");
  457.  
  458.     if(cb->errlog != NULLLIST){
  459.         retmail(cb);
  460.         unlink(cb->wname);    /* unlink workfile */
  461.         unlink(cb->tname);    /* unlink textfile */
  462.     }
  463.     if(cb->tfile != NULLFILE) {
  464.         Fclose(cb->tfile);
  465.     }
  466.     close_s(cb->s);
  467.     del_session(cb);
  468. }
  469.  
  470. /* This is the routine that gets called every so often to do outgoing
  471.  * mail processing. When called with a null argument, it runs the entire
  472.  * queue; if called with a specific non-zero IP address from the remote
  473.  * kick server, it only starts up sessions to that address.
  474.  */
  475. int
  476. smtptick(void *t)
  477. {
  478.     struct smtpcli *cb;
  479.     struct smtp_job *jp;
  480. #ifdef SMTPTRACE
  481.     struct list *ap;
  482. #endif
  483.     char fstring[MAXPATH], from[LINELEN], to[LINELEN], tmpstring[LINELEN];
  484.     char wfilename[13], prefix[9], *cp, *cp1;
  485.     FILE *wfile;
  486.     int32 destaddr, target = (int32)t;
  487.  
  488. #ifdef SMTPTRACE
  489.     if (Smtptrace) {
  490.         tprintf("SMTP daemon entered, target = %s\n",inet_ntoa(target));
  491.     }
  492. #endif
  493.     if(availmem() == 0) {
  494.         /* Memory is tight, don't do anything */
  495.         return 0;
  496.     }
  497.     sprintf(fstring,"%s/*.wrk",Mailqdir);
  498.  
  499.     for(filedir(fstring,0,wfilename); *wfilename != '\0'; filedir(fstring,1,wfilename)) {
  500.         pwait(NULL);
  501.  
  502.         /* save the prefix of the file name which it job id */
  503.         cp = wfilename;
  504.         cp1 = prefix;
  505.  
  506.         while(*cp && *cp != '.') {
  507.             *cp1++ = *cp++;
  508.         }
  509.         *cp1 = '\0';
  510.  
  511.         /* lock this file from the smtp daemon */
  512.         if(mlock(Mailqdir,prefix)) {
  513.             continue;
  514.         }
  515.         sprintf(tmpstring,"%s/%s",Mailqdir,wfilename);
  516.  
  517.         if((wfile = Fopen(tmpstring,READ_TEXT,0,0)) == NULLFILE) {
  518.             /* probably too many open files */
  519.             /* continue to next message. The failure may be temporary */
  520.             rmlock(Mailqdir,prefix);
  521.             continue;
  522.         }
  523.         fgets(tmpstring,sizeof(tmpstring),wfile);    /* read 'target host' */
  524.         rip(tmpstring);
  525.         fgets(from,sizeof(from),wfile);                /* read 'from' */
  526.         rip(from);
  527.         fgets(to,sizeof(to),wfile);                    /* read 'to' */
  528.         rip(to);
  529.  
  530.         if((destaddr = mailroute(tmpstring)) == 0) {
  531.             int perms;
  532.             
  533.             if((perms = userlogin(IPPORT_SMTP,0,to)) == 0) {
  534.                 if((perms = Smtpbbs) == 0) {
  535.                     perms = MAIL;
  536.                 }
  537.             }    
  538.             if(perms == BBS || perms == NEWS) {
  539.                 destaddr = Ip_addr;
  540.             } else {
  541.                 Fclose(wfile);
  542.                 rmlock(Mailqdir,prefix);
  543.                 tprintf(Badhost,tmpstring);
  544.                 continue;
  545.             }
  546.         }
  547.         if(target && destaddr != target) {
  548.             Fclose(wfile);
  549.             rmlock(Mailqdir,prefix);
  550.             continue;
  551.         }
  552.         if(!testdelv(destaddr)) {
  553.             Fclose(wfile);
  554.             rmlock(Mailqdir,prefix);
  555.             continue;
  556.         }
  557.         for(cb = Smtpcli; cb != NULLSMTPCLI; cb = cb->next) {
  558.             if(cb->ipdest == destaddr) {
  559.                 break;
  560.             }
  561.         }
  562.         if(cb == NULLSMTPCLI) {
  563.             /* there are enough processes running already */
  564.             if(Smtpsessions >= Smtpmaxcli) {
  565. #ifdef SMTPTRACE
  566.                 if (Smtptrace) {
  567.                     tputs("SMTP: too many processes\n");
  568.                 }
  569. #endif
  570.                 Fclose(wfile);
  571.                 rmlock(Mailqdir,prefix);
  572.                 break;
  573.             }
  574.             cb = mxallocw(sizeof(struct smtpcli));
  575.             cb->next  = Smtpcli;
  576.             Smtpcli   = cb;
  577.  
  578.             cb->buf   = mxallocw(LINELEN);
  579.             cb->wname = mxallocw(strlen(Mailqdir) + JOBNAME + 2);
  580.             cb->tname = mxallocw(strlen(Mailqdir) + JOBNAME + 2);
  581.             cb->ipdest = destaddr;
  582.             cb->destname = strxdup(tmpstring);
  583.  
  584.             Smtpsessions++;            /* number of connections active */
  585.         } else {
  586.             if(cb->lock) {
  587.                 /* This system is already is sending mail lets not
  588.                 * interfere with its send queue.
  589.                 */
  590.                 Fclose(wfile);
  591.                 rmlock(Mailqdir,prefix);
  592.                 continue;
  593.             }
  594.         }
  595.         if((jp = setupjob(cb,prefix,from)) == NULLJOB) {
  596.             Fclose(wfile);
  597.             rmlock(Mailqdir,prefix);
  598.             del_session(cb);
  599.             break;
  600.         }
  601.         do {
  602.             rip(to);
  603.             if(addlist(&jp->to,to,DOMAIN) == NULLLIST) {
  604.                 del_session(cb);
  605.                 break;
  606.             }
  607.         } while(fgets(to,sizeof(to),wfile) != NULL);
  608.  
  609.         Fclose(wfile);
  610.  
  611. #ifdef SMTPTRACE
  612.         if (Smtptrace) {
  613.             for(ap = jp->to; ap != NULLLIST; ap = ap->next) {
  614.                 tprintf("SMTP queue job %s From: %s To: %s\n",
  615.                     prefix,from,ap->val);
  616.             }
  617.         }
  618. #endif
  619.     }
  620.     /* start sending that mail */
  621.     for(cb = Smtpcli; cb != NULLSMTPCLI && !cb->lock; cb = cb->next) {
  622.         sprintf(cb->tname,"%s/%s.txt",Mailqdir,cb->jobq->jobname);
  623.         sprintf(cb->wname,"%s/%s.wrk",Mailqdir,cb->jobq->jobname);
  624.         newproc("SMTP send",2048,smtp_send,0,cb,NULL,0);
  625.  
  626. #ifdef SMTPTRACE
  627.         if (Smtptrace) {
  628.             tprintf("SMTP Trying Connection to %s\n",inet_ntoa(cb->ipdest));
  629.         }
  630. #endif
  631.     }
  632.     return 0;
  633. }
  634.  
  635. /* ----------------------- SMTP Client subcmds ----------------------- */
  636.  
  637. static int
  638. dosmtpbatch(int argc,char **argv,void *p)
  639. {
  640.     return setbool(&Smtpbatch,"SMTP batch",argc,argv);
  641. }
  642.  
  643. static int
  644. dosmtpbbs(int argc,char **argv,void *p)
  645. {
  646.     return setbool(&Smtpbbs,"SMTP to BBS",argc,argv);
  647. }
  648.  
  649. static int
  650. dosmtpgate(int argc,char **argv,void *p)
  651. {
  652.     int32 n = 0;
  653.  
  654.     if(argc < 2) {
  655.         tprintf("SMTP gateway: %s\n",inet_ntoa(Gateway));
  656.     } else if((n = resolve(argv[1])) == 0){
  657.         tprintf(Badhost,argv[1]);
  658.         return 1;
  659.     } else {
  660.         Gateway = n;
  661.     }
  662.     return 0;
  663. }
  664.  
  665. static int
  666. dosmtpkick(int argc,char **argv,void *p)
  667. {
  668.     int32 addr = 0;
  669.  
  670.     if(argc > 1 && (addr = resolve(argv[1])) == 0){
  671.         tprintf(Badhost,argv[1]);
  672.         return 1;
  673.     }
  674.     smtptick((void *)addr);
  675.     return 0;
  676. }
  677.  
  678. /* kill a job in the mqueue */
  679. static int
  680. dosmtpkill(int argc,char **argv,void *p)
  681. {
  682.     char c, *cp, s[LINELEN];
  683.  
  684.     sprintf(s,"%s/%s.lck",Mailqdir,argv[1]);
  685.     cp = strrchr(s,'.');
  686.  
  687.     if(access(s,0) == 0) {
  688.         Current->ttystate.echo = Current->ttystate.edit = 0;
  689.         c = keywait("Warning, the job is locked by SMTP. Remove (y/n)? ",0);
  690.         Current->ttystate.echo = Current->ttystate.edit = 1;
  691.         if(c != 'y') {
  692.             return 0;
  693.         }
  694.         unlink(s);
  695.     }
  696.     strcpy(cp,".wrk");
  697.     unlink(s);
  698.     strcpy(cp,".txt");
  699.     unlink(s);
  700.  
  701.     return 0;
  702. }
  703.  
  704. /* list jobs wating to be sent in the mqueue */
  705. static int
  706. dosmtplist(int argc,char **argv,void *p)
  707. {
  708.     char fstring[MAXPATH], tstring[MAXPATH], line[20], host[80];
  709.     char from[80], to[80], status, *cp;
  710.     struct stat stbuf;
  711.     struct tm *tminfo;
  712.     FILE *fp;
  713.  
  714.     /* Enable the more mechanism */
  715.     Current->flowmode = Cooked;
  716.  
  717.     tputs("S     Job    Size Date  Time  Host             From\n");
  718.  
  719.     sprintf(fstring,"%s/*.wrk",Mailqdir);
  720.  
  721.     filedir(fstring,0,line);
  722.  
  723.     while(*line != '\0') {
  724.         sprintf(tstring,"%s/%s",Mailqdir,line);
  725.  
  726.         if((fp = Fopen(tstring,READ_TEXT,0,1)) == NULLFILE) {
  727.             continue;
  728.         }
  729.         if((cp = strrchr(line,'.')) != NULLCHAR) {
  730.             *cp = '\0';
  731.         }
  732.         sprintf(tstring,"%s/%s.lck",Mailqdir,line);
  733.         status = (access(tstring,0)) ? ' ' : 'L';
  734.         sprintf(tstring,"%s/%s.txt",Mailqdir,line);
  735.         stat(tstring,&stbuf);
  736.         tminfo = localtime(&stbuf.st_ctime);
  737.         fgets(host,sizeof(host),fp);
  738.         rip(host);
  739.         fgets(from,sizeof(from),fp);
  740.  
  741.         tprintf("%c %7s %7ld %02d/%02d %02d:%02d %-16.16s %s",
  742.             status,
  743.             line,
  744.             stbuf.st_size,
  745.             tminfo->tm_mon+1,
  746.             tminfo->tm_mday,
  747.             tminfo->tm_hour,
  748.             tminfo->tm_min,
  749.             host,
  750.             from);
  751.  
  752.         while(fgets(to,sizeof(to),fp) != NULLCHAR) {
  753.             tprintf("  To: %s",to);
  754.         }
  755.         Fclose(fp);
  756.         filedir(fstring,1,line);
  757.     }
  758.     Current->flowmode = Raw;
  759.     return 0;
  760. }
  761.  
  762. static int
  763. dosmtpmaxcli(int argc,char **argv,void *p)
  764. {
  765.     return setintrc(&Smtpmaxcli,"SMTP maxcli",argc,argv,1,MAXSESSIONS);
  766. }
  767.  
  768. static int
  769. dosmtpmode(int argc,char **argv,void *p)
  770. {
  771.     if (argc < 2) {
  772.         tprintf("SMTP mode: %s\n",Smtpmode ? "Queue" : "Route");
  773.     } else {
  774.         switch(*argv[1]) {
  775.         case 'q':
  776.             Smtpmode = QUEUE;
  777.             break;
  778.         case 'r':
  779.             Smtpmode = ROUTE;
  780.             break;
  781.         default:
  782.             tputs("Usage: smtp mode [queue|route]\n");
  783.             break;
  784.         }
  785.     }
  786.     return 0;
  787. }
  788.  
  789. static int
  790. dosmtpquiet(int argc,char **argv,void *p)
  791. {
  792.     return setintrc(&Smtpquiet,"SMTP quiet",argc,argv,0,3);
  793. }
  794.  
  795. #ifdef LZW
  796. static int
  797. dosmtplzw(int argc,char **argv,void *p)
  798. {
  799.     return setbool(&Smtplzw,"SMTP LZW",argc,argv);
  800. }
  801. #endif
  802.  
  803. #ifdef SMTPTRACE
  804. static int
  805. dosmtptrace(int argc,char **argv,void *p)
  806. {
  807.     return setbool(&Smtptrace,"SMTP tracing",argc,argv);
  808. }
  809. #endif
  810.  
  811. int
  812. dosmtp(int argc,char **argv,void *p)
  813. {
  814.     struct cmds Smtpcmds[] = {
  815.         "batch",        dosmtpbatch,    0,    0,    NULLCHAR,
  816.         "bbs",            dosmtpbbs,        0,  0,  NULLCHAR,
  817.         "delete",        dosmtpkill,        0,    2,    "smtp delete <jobnumber>",
  818.         "gateway",        dosmtpgate,        0,    0,    NULLCHAR,
  819.         "kick",            dosmtpkick,        0,    0,    NULLCHAR,
  820.         "list",            dosmtplist,        0,    0,    NULLCHAR,
  821. #ifdef LZW
  822.         "lzw",            dosmtplzw,        0,  0,  NULLCHAR,
  823. #endif
  824.         "maxclient",    dosmtpmaxcli,    0,    0,    NULLCHAR,
  825.         "mode",            dosmtpmode,        0,    0,    NULLCHAR,
  826.         "quiet",        dosmtpquiet,    0,    0,    NULLCHAR,
  827. #ifdef SMTPTRACE
  828.         "trace",        dosmtptrace,    0,     0,    NULLCHAR,
  829. #endif
  830.         NULLCHAR,
  831.     };
  832.     return subcmd(Smtpcmds,argc,argv,p);
  833. }
  834.  
  835.